# -*- coding:utf-8 -*-
# @Time : 2022/6/8 上午11:05 
# @Author : zdy
# @File : UIPowerParam.py
# desc:
import copy
import math
import threading
from time import sleep

from Class.GraphBase import GraphBase
from Class.LSFit import Fit
from UI.PowerParams import Ui_Dialog
from Class.Devices import *
from Class.DeviceBase import Userparam, PIU
from importQT import *
import pyqtgraph as pg


class UIPowerParam(QDialog, Ui_Dialog):
    sigRefresh = pyqtSignal()

    def __init__(self):
        super(UIPowerParam, self).__init__()
        self.setupUi(self)
        self.setWindowFlags(Qt.WindowCloseButtonHint)
        self.setFixedSize(self.width(), self.height())
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.applyResource()
        self.row = -1  # 正在进行的行
        self.breadUI = False
        self.readU = 0.0
        self.readI = 0.0
        self.sigRefresh.connect(self.refreshTW)
        device.card.sigReceive.connect(self.monitorRefresh)
        self.graphBase1 = GraphBase(self, title='电流参数拟合')
        self.IWidget = self.graphBase1.graphwiget
        self.horizontalLayout.addWidget(self.IWidget)
        self.curveI = []
        self.graphBase2 = GraphBase(self, title='电压参数拟合')
        self.UWidget = self.graphBase2.graphwiget
        self.horizontalLayout.addWidget(self.UWidget)
        self.curveU = []
        paramI = device.findInUserparams(Userparam.Current)
        self.lblIk2.setText(str(paramI[0]))
        self.lblIk.setText(str(paramI[1]))
        self.lblIc.setText(str(paramI[2]))
        paramU = device.findInUserparams(Userparam.Volt)
        self.lblUk.setText(str(paramU[1]))
        self.lblUc.setText(str(paramU[2]))
        self.piuItems = copy.deepcopy(device.getPIUItems())
        if len(self.piuItems) == 0:
            self.piuItems.append(PIU(2.0))
            self.piuItems.append(PIU(4.0))
            self.piuItems.append(PIU(5.0))
            self.piuItems.append(PIU(6.0))
            self.piuItems.append(PIU(7.0))
        else:
            Ix =[]
            Iy = []
            Ux = []
            Uy = []
            for i in self.piuItems:
                i:PIU
                Ix.append(i.readI)
                Iy.append(i.realI)
                Ux.append(i.readU)
                Uy.append(i.realU)
            self.painI(Ix, Iy, [paramI[2], paramI[1], paramI[0]])
            self.painU(Ux, Uy, [paramU[2], paramU[1], paramU[0]])
            pass

        self.twParam.setColumnCount(5)
        # 设置表头粗体
        self.twParam.setHorizontalHeaderLabels(['输出电压', '传感器电流值', '实际电流值', '传感器电压值', '实际电压值'])
        font = self.twParam.horizontalHeader().font()
        font.setBold(True)
        self.twParam.horizontalHeader().setFont(font)
        self.twParam.horizontalHeader().setSectionsClickable(False)  # 表头不可点击
        self.twParam.horizontalHeader().setStretchLastSection(True)  # 最后一列填充
        for piuitem in self.piuItems:
            item: PIU
            row = self.twParam.rowCount()
            self.twParam.insertRow(row)
            item = QTableWidgetItem()
            item.setData(Qt.DisplayRole, piuitem.setU)
            self.twParam.setItem(row, 0, item)
            item1 = QTableWidgetItem()
            item1.setData(Qt.DisplayRole, piuitem.readI)
            self.twParam.setItem(row, 1, item1)
            item2 = QTableWidgetItem()
            item2.setData(Qt.DisplayRole, piuitem.realI)
            self.twParam.setItem(row, 2, item2)
            item3 = QTableWidgetItem()
            item3.setData(Qt.DisplayRole, piuitem.readU)
            self.twParam.setItem(row, 3, item3)
            item4 = QTableWidgetItem()
            item4.setData(Qt.DisplayRole, piuitem.realU)
            self.twParam.setItem(row, 4, item4)
        self.btnSave.clicked.connect(self.btnSave_clicked)
        self.btnStop.clicked.connect(self.btnStop_clicked)
        self.btnCalibrate.clicked.connect(self.btnCalibrate_clicked)

    def applyResource(self):
        self.setWindowIcon(getIcon())

    def painI(self, Ix, Iy, param):
        self.curveI.append(self.IWidget.plot(x=Ix, y=Iy, pen=None, symbol='o'))#,symbolBrush=(100, 100, 255, 50)
        minv = min(Ix)
        maxv = max(Ix)
        step = (maxv - minv)/50#绘制多点，让曲线更平滑
        Ix_=[]
        Iy_ = []
        for i in range(50):
            v = minv +step * i
            Ix_.append(v)
            Iy_.append(v*v*param[2] + v*param[1] + param[0])
        self.curveI.append(self.IWidget.plot(x=Ix_, y=Iy_, pen=pg.mkPen(color="r", width=2)))
        Ir = Fit.Coefficient(Ix,Iy)
        self.lblrI.setText("r = %.3f" % Ir)

    def clearCurve(self):
        for i in self.curveU:
            i.clear()
            self.UWidget.removeItem(i)
        self.curveU.clear()
        for i in self.curveI:
            i.clear()
            self.IWidget.removeItem(i)
        self.curveI.clear()

    def painU(self, Ux, Uy, param):
        self.curveU.append(self.UWidget.plot(x=Ux, y=Uy, pen=None, symbol='o'))#,symbolBrush=(100, 100, 255, 50)
        Uy_=[]
        for i in Ux:
            Uy_.append(i*param[1] + param[0])
        self.curveU.append(self.UWidget.plot(x=Ux, y=Uy_, pen=pg.mkPen(color="r", width=2)))
        Ur = Fit.Coefficient(Ux, Uy)
        self.lblrU.setText("r = %.3f" % Ur)

    def btnCalibrate_clicked(self):
        if not device.monitor.furnaceStatus:
            QMessageBox.warning(self, "提示","升炉后才可进行功率参数校正")
            return
        self.row += 1
        if self.row == 0:
            self.btnSave.setEnabled(False)
            for i in range(self.twParam.rowCount()):
                self.twParam.item(i, 1).setData(0, 0.0)
                self.twParam.item(i, 2).setData(0, 0.0)
                self.twParam.item(i, 3).setData(0, 0.0)
                self.twParam.item(i, 4).setData(0, 0.0)
            self.clearCurve()
            self.breadUI = True
        if self.row == self.twParam.rowCount():
            self.stop2Calibrate()
        if self.row < self.twParam.rowCount() and self.row >= 0:
            self.activateItem()
            self.outputVolt()
            self.btnCalibrate.setText("继续")

    def stop2Calibrate(self):
        self.breadUI = False
        device.controlSCR(0)
        if self.row == self.twParam.rowCount():
            Ix = []
            Iy = []
            Ux =[]
            Uy = []
            for i in range(self.twParam.rowCount()):
                Ix.append(self.twParam.item(i,1).data(0))
                Iy.append(self.twParam.item(i, 2).data(0))
                Ux.append(self.twParam.item(i, 3).data(0))
                Uy.append(self.twParam.item(i, 4).data(0))
            paramI = self.multiLIne(Ix, Iy, len(Ix), 2)
            self.lblIk2.setText("%.1f" % paramI[2])
            self.lblIk.setText("%.1f" % paramI[1])
            self.lblIc.setText("%.1f" % paramI[0])
            self.painI(Ix, Iy, paramI)
            paramU = self.multiLIne(Ux, Uy, len(Ux), 1)
            self.lblUk.setText("%.1f" % paramU[1])
            self.lblUc.setText("%.1f" % paramU[0])
            self.painU(Ux, Uy, paramU)
        self.row = -1
        self.btnSave.setEnabled(True)
        self.btnCalibrate.setText("校正")
        pass

    def activateItem(self):
        pass

    def monitorRefresh(self, pts):
        if self.breadUI:
            self.readU = pts.ChannelV[device.systemconfig.daq.ADVolt]
            self.readI = pts.ChannelV[device.systemconfig.daq.ADCurrent]
            self.sigRefresh.emit()

    def outputVolt(self):
        volt = self.twParam.item(self.row, 0).data(0)
        device.controlSCR(volt)

    def refreshTW(self):
        if self.row >= 0 and self.row < self.twParam.rowCount():
            self.twParam.item(self.row, 1).setData(0, self.readI)
            self.twParam.item(self.row, 3).setData(0, self.readU)

    def btnStop_clicked(self):
        self.stop2Calibrate()

    def btnSave_clicked(self):
        device.updateUserparams(Userparam.Current, [float(self.lblIk2.text()), float(self.lblIk.text()), float(self.lblIc.text())])
        device.updateUserparams(Userparam.Volt, [0, float(self.lblUk.text()), float(self.lblUc.text())])
        self.piuItems.clear()
        for i in range(self.twParam.rowCount()):
            p = PIU()
            p.setU = self.twParam.item(i,0).data(0)
            p.readI = self.twParam.item(i, 1).data(0)
            p.realI = self.twParam.item(i, 2).data(0)
            p.readU = self.twParam.item(i, 3).data(0)
            p.realU = self.twParam.item(i, 4).data(0)
            self.piuItems.append(p)
        device.setPIUItems(self.piuItems)
        self.accept()
        self.close()


    def multiLIne(self, arrX, arrY, length, dimension):
        n = dimension +1
        guass = [[0 for i in range(n+1)] for i in range(n)]
        for i in range(n):
            for j in range(n):
                guass[i][j] = self.sumArr(arrX, j+i, length)
            guass[i][n] = self.sumArr1(arrX, i, arrY,1 , length)
        return self.computGauss(guass, n)

    def sumArr(self, arr, n, length):
        s =0
        for i in range(length):
            if arr[i] !=0 or n != 0:
                s = s+ math.pow(arr[i], n)
            else:
                s = s+1
        return s

    def sumArr1(self, arr1, n1,arr2,n2, length):
        s =0
        for i in range(length):
            if (arr1[i] !=0 or n1 != 0) and (arr2[i] !=0 or n2 !=0):
                s = s+ math.pow(arr1[i], n1) * math.pow(arr2[i], n2)
            else:
                s = s+1
        return s

    def computGauss(self, guass, n):
        x = [0.0 for i in range(n)]
        for j in range(n):
            max = 0.0
            k = j
            for i in range(j,n):
                if abs(guass[i][j]) > max:
                    max = guass[i][j]
                    k = i
            if k !=j:
                for m in range(j,n+1):
                    temp = guass[j][m]
                    guass[j][m] = guass[k][m]
                    guass[k][m] = temp
            if max ==0:
                return x
            for i in range(j+1,n):
                s = guass[i][j]
                for m in range(j,n+1):
                    guass[i][m] = guass[i][m] - guass[j][m] * s/guass[j][j]
        for i in range(n-1, -1, -1):
            s = 0
            for j in range(i+1,n):
                s = s+ guass[i][j] *x[j]
            x[i] = (guass[i][n] -s )/guass[i][i]
        return x

    def closeEvent(self, event) -> None:
        self.sigRefresh.disconnect(self.refreshTW)
